// © Copyright 1993-94 Apple Computer, Inc, All Rights Reserved

constant kAppSymbol := '|Slurp:PIEDTS|;
constant kPackageName := '|Slurp:PIEDTS|;
constant kAppObject := '["soup","soups"];

constant kSoupName := kPackageName;
constant kSoupIndexes := '[/* {structure: slot, path: name.first, type: string} */];


func zGetSound(name, file)
begin;
   local rf := OpenResFileX(file);
   local snd := {sndFrameType: 'simpleSound,
     samples: GetSndAsSamples(name),
     samplingRate: 22026.43172,
     dataType: 1,
     compressionType: 0};
   CloseResFileX(rf);
   return snd;
end;

func zGetSound11(name, file)
begin;
   local rf := OpenResFileX(file);
   local snd := {sndFrameType: 'simpleSound,
     samples: GetSndAsSamplesRate11KHz(name),
     samplingRate: 11013.21586,
     dataType: 1,
     compressionType: 0};
   CloseResFileX(rf);
   return snd;
end;

homeDir := "Beeld:Desktop Folder:New Slurp:";

theSlurpSound := zGetSound11("Slurping", "Slurping");

// ---- End Project Data ----


// ---- File SlurpBaseView.t ----
slurpBaseView :=
   {newEntry: nil,
    viewSetupDoneScript:
      func()
      begin
         :newStatus("Click Receive..., the send file from Mac...");
      
         self.commEndPt := { _proto:   protoSerialProtocol,
                             _parent:  self,
                             slurpBaseView:  self};
      
         PlaySound(slurpSound);
      end,
    epDisconnect:
      func()
      begin
      //   RemoveSlot(commEndPt, 'slurpBaseView);
      
         commEndPt:Abort();
      
         commEndPt:Release();
      end,
    viewQuitScript:
      func()
      begin
      //in your viewQuitScript, call
      //   :UnRegisterCardSoup(kSoupName);
      
         if StrEqual(receiveBtn.text, "Disconnect") then begin
            RemoveSlot(commEndPt, 'slurpBaseView);
            :epDisconnect();
         end;
      
         inherited:?viewQuitScript();
      end,
    RegisterCardSoup:
      func(soupName,soupIndexes,appSymbol,appObject)
        //returns a union-soup for your app to use
        begin
          //first check for system provided function
          if functions.RegisterCardSoup then
            return RegisterCardSoup(soupName,soupIndexes,appSymbol,appObject);
      
          CreateAppSoup(soupName,soupIndexes,EnsureInternal([appSymbol]),EnsureInternal(appObject));
                 
          //ensure your soup will exist on stores which later become available
          AddArraySlot(CardSoups,soupName);
          AddArraySlot(CardSoups,soupIndexes);
          
          //ensure your soup exists on all currently available stores
          local store;
          foreach store in GetStores() do
            if NOT store:IsReadOnly() AND NOT store:HasSoup(soupName) then
              store:CreateSoup(soupName,soupIndexes);
          
          GetUnionSoup(soupName);
        end,
    entrySpec: nil,
    addNewEntry:
      /* addNewEntry
            Add a new entry into the soup.  
      
      	Slots used:
         entryIndex,entryString
         newEntry,entrySpec
         testSoup
         testSoupName
         
      		
      	Methods used:
      		n/a
      	
      	Assumptions:
      		none
      */
      func(s)
      begin
         // Setup the input buffer.  Our inputScripts give us
         // a line at a time.
         entryIndex := 0;
         entryString := s;
      
      //   :newStatus("addNewEntry: before currentEntryDisplay");
         currentEntryDisplay:newMsg(s);
      //   :newStatus("addNewEntry: after currentEntryDisplay");
      
         // Now initialize the new entry by cloning the
         // entry specification we got earlier.  This is
         // a frame with the same slots as a soup entry,
         // with sample slot values that are used to
         // specify the desired type for the data.
         newEntry := Clone(entrySpec);
         newEntry := :buildEntry(newEntry);
      //   :newStatus("addNewEntry: after buildEntry");
      
         // Fix the sortOn slot in the entry.
         // The sortOn slot contains a reference to the string in
         // either the names.last slot or the company slot.
         // This allows the Names app to keep a single index
         // on the sortOn slot, while still sorting by
         // either the names.last or company slotc values...
         if newEntry.sortOn = 'name then
            newEntry.sortOn := SetClass(newEntry.name.last, 'name);
         else
            newEntry.sortOn := SetClass(newEntry.company, 'company);
      
         // Now, assuming we have an entry, add it to
         // the default storage device.
         targetSoup:AddToDefaultStore(newEntry);
      //   :newStatus("addNewEntry: after AddToDefaultStore");
      
         // Flush our changes...
         targetSoup:Flush();
      //   :newStatus("addNewEntry: after targetSoup");
      
         // Tell the rest of the world that something has
         // changed.
         BroadcastSoupChange(targetSoupName);
      //   :newStatus("addNewEntry: after BroadcastSoupChange");
      
         numEntries := numEntries + 1;
         SetValue(entriesSlurped, 'text, "" & numEntries);
      
      //   :newStatus("addNewEntry: after addNewEntry");
      end,
    targetSoup: nil,
    newSoupName:
      func(s)
      begin
        :newStatus("Setting new soup name...");
         self.targetSoupName := SubStr(s, 0, StrPos(s, "\n", 0));
         self.targetSoup := GetUnionSoup(targetSoupName);
         SetValue(soupNameDisplay, 'text, targetSoupName);
         :newStatus("Waiting for entrySpec...");
      end,
    viewBounds: {left: -2, top: 2, right: 227, bottom: 239},
    _proto: protoApp,
    epInit:
      func()
      begin
         local   epErr := nil;
      
         commEndPt := { _proto:   protoSerialProtocol,
                        _parent:  self,
                        slurpBaseView:  self};
      
         :newStatus("Instantiating endpoint...");
         epErr := commEndPt:Instantiate(commEndPt, nil);
       
         Perform(epState, 'showState, ["After Instantiate:"]);
      
         if epErr then
         begin
            :newStatus("Instantiate Error:" && NumberStr(epErr));
            return;
         end;
         else
            :newStatus("Instantiating endpoint...done.");
      
         :newStatus("Ready to connect...");
      
         numEntries := 0;
      end,
    protoSerialProtocol:
      {
         _proto: protoEndpoint,         // the basic endpoint
      
         configOptions: [
            { label: kCMSAsyncSerial, type: 'service, opCode: opSetRequired },
            { label: kCMOSerialIOParms, type: 'option, opCode: opSetNegotiate,
               data: { bps: k9600bps, dataBits: k8DataBits, stopBits: k1StopBits, parity: kNoParity } },
            { label: kCMOInputFlowControlParms, type: 'option, opCode: opSetNegotiate,
               data: { xonChar: unicodeDC1, xoffChar: unicodeDC3, useSoftFlowControl: true, useHardFlowControl: nil } },
            ],   
      
         exceptionHandler: func(exception)
         begin
            Perform(endpoint.slurpBaseView, 'newStatus, ["exceptionHandler called..."]);
         end,
      
         waitForSoupName:
         {
            InputForm: 'string,
            endCharacter: UnicodeCR,
       
            InputScript: func(endpoint, s)
            begin
               Perform(endpoint.slurpBaseView, 'newSoupName, [s]);
               endpoint:SetInputSpec(endpoint.waitForEntrySpec);
            end,
            discardAfter: 1000,
         },
      
         waitForEntrySpec:
         {
            InputForm: 'string,
            endCharacter: UnicodeCR,
       
            InputScript: func(endpoint, s)
            begin
               Perform(endpoint.slurpBaseView, 'buildEntrySpec, [s]);
               endpoint:SetInputSpec(endpoint.waitForEntries);
            end,
            discardAfter: 1000,
         },
      
         waitForEntries:
         {
            InputForm: 'string,
            endCharacter: UnicodeCR,
            InputScript: func(endpoint, s)
            begin
               if BeginsWith(s, "BYE!") then
               begin
                  Perform(endpoint.slurpBaseView, 'epDisconnect, []);
                  SetValue(endpoint.slurpBaseView.receiveBtn, 'text, "Receive...");
                  Perform(endpoint.slurpBaseView, 'newStatus, ["Slurp complete - Tap Receive... to Slurp another..."]);
               end;
               else
               begin
                  Perform(endpoint.slurpBaseView, 'addNewEntry, [s]);
                  endpoint:SetInputSpec(endpoint.waitForEntries);
               end;
            end,
            discardAfter: 1000,
         }
      },
    nextInputString:
      func()
      begin
         local sPos, s;
      
         sPos := StrPos(entryString, "\t", entryIndex);
         if not sPos then
            sPos := StrPos(entryString, "\n", entryIndex);
      
         s := SubStr(entryString, entryIndex, sPos - entryIndex);
         entryIndex := sPos + 1;
         s;
      end,
    entryString: "Text",
    title: "Slurp",
    commEndPt: nil,
    entrySpecFunc:
      func()
      begin
      end,
    buildEntrySpec:
      /* BuildEntrySpec
      	Compile a WallyScript frame definition and get the resulting object.
      
      	Slots used:
      		entrySpec, entrySpecFunc
      		
      	Methods used:
      		n/a
      	
      	Assumptions:
      		
      */
      func(s)
      begin
         :newStatus("BuildEntrySpec: before Compile");
         entrySpecFunc := Compile(s);
         :newStatus("BuildEntrySpec: before entrySpecFunc()");
         entrySpec := :entrySpecFunc();
         :newStatus("BuildEntrySpec: after entrySpecFunc()");
      end,
    epConnect:
      func()
      begin
         local   epErr := nil;
      
         :newStatus("Connecting...");
         epErr := commEndPt:Connect(nil, nil);
         Perform(epState, 'showState, ["After Connect:"]);
         if epErr then
            :newStatus("Error trying to connect:" && NumberStr(epErr));
         else begin
            :newStatus("Connecting...done.");
            :newStatus("Setting input spec...");
            commEndPt:SetInputSpec(commEndPt.waitForSoupName);
            Perform(epState, 'showState, ["After SetInputSpec:"]);
            :newStatus("Setting input spec...done.");
            :newStatus("Waiting for soup name...");
         end;
      end,
    epDeferredDisconnect:
      func()
      begin
         commEndPt:Abort();
      
         commEndPt:Release();
      
      //   commEndPt:Dispose();
      end,
    newStatus:
      func(msg)
      begin
         statusBox:newMsg(msg);
         RefreshViews();
      end,
    slurpSound: theSlurpSound,
    entryIndex: nil,
    numEntries: nil,
    debug: "slurpBaseView",
    buildEntry:
      /* BuildEntry
      	Convert a tab delimited string of data into a soup entry (ie. frame)
      
      	Slots used:
      		n/a
      		
      	Methods used:
      		matchTypes, nextInputString
      	
      	Assumptions:
      		currentFrameOrArray parameter is initialized to a frame.
      */
      func(currentFrameOrArray)
      begin
      	// For each slot in the frame or each element in the array.
      	// The cool thing about foreach is that it doesn't care.  By
      	// using the path foreach creates, we can even assign values
      	// with the exact same code...
      	foreach path, value in currentFrameOrArray do begin
      		// Get the real class of the first slot/element.  In the
      		// case of the "Names" soup, the frame containing the
      		// person's name has a class slot set to 'person.  Because
      		// of this, the ClassOf function returns 'person instead
      		// of 'frame.  Using PrimClassOf (ie. Prim(itive)ClassOf)
      		// we can find out the real type.
      		local pClass := PrimClassOf(value);
      		
      		// Since frames/arrays can contain other frames/arrays,
      		// we can use recursion to simplify the function.  If
      		// we run across an element that is a frame/array, we
      		// just call ourself with the new path.  We Clone the
      		// spec value to reduce garbage collection and prevent
      		// having seperate code for creating frames and arrays.
      		if pClass = 'frame or pClass = 'array then begin
      			currentFrameOrArray.(path) := Clone(value);
      			:BuildEntry(currentFrameOrArray.(path));
      		end; else
      		
      		// Finally the real work.  If the slot value is not a
      		// frame/array, assign the new value.  getNextField
      		// returns the next tab-delimited string from the input
      		// buffer.  matchTypes is used to coerce the string
      		// into the type specified by value.
      		// NOTE 
      		//	We pass value instead of ClassOf(value) because
      		//	some types are specified using the contents of
      		//	a string.  See matchTypes for more info...
      			currentFrameOrArray.(path) := :matchTypes(:nextInputString(), value);
       end;
       currentFrameOrArray;
      end,
    matchTypes:
      /* matchTypes
      	Coerce the type of a value to match another.  
      
      	Slots used:
      		n/a
      		
      	Methods used:
      		n/a
      	
      	Assumptions:
         The type specified by valueType is never Frame or Array.
         If the type is string, then the real type is specified
         as a symbol stored within that string.  For example,
            "string"   Coerce the value to type string
            "date"     Coerce the value into a date value
         If the string is specified as:
            "stringWithClass"
         then the valueString is made into a symbol, and the
         type of the string becomes that symbol (ie. name, company). 
       
      */
      func(valueString, valueType)
      begin
         local theType := ClassOf(valueType);
      
         // If valueType is string, get real type from string contents.
         if theType = 'string then
            theType := MakeSymbol(valueType);
      	
      //   :newStatus("matchTypes:" && valueString && theType);
      
         if theType = 'string then
            valueString;
         else
         if theType = 'int then
            RintToL(StringToNumber(valueString));
         else
         if theType = 'real then
            StringToNumber(valueString);
         else
         if theType = 'symbol then
            MakeSymbol(valueString);
         else
         if theType = 'date then
            StringToDate(valueString);
         else
         // Special, extra-strange stuff for handling the Names soup.
         // Other soups may not require this code...
         if theType = 'stringWithClass then
            MakeSymbol(valueString);
         else begin
            if StrLen(valueString) > 0 then
               SetClass(valueString, theType);
         end;
      end,
    targetSoupName: nil,
    UnRegisterCardSoup:
      func(soupName)
        begin
          //first check for system provided function
          if functions.UnRegisterCardSoup then
            return UnRegisterCardSoup(soupName);
      
          local pos := ArrayPos(CardSoups,soupName,0,func(x,y) ClassOf(y)='String AND StrEqual(x,y));
          if pos then ArrayRemoveCount(CardSoups,pos,2);
        end
   };

statusBoxLabel := /* child of slurpBaseView */
   {text: "Slurp Status:",
    viewBounds: {left: 79, top: 18, right: 149, bottom: 34},
    viewFont: simpleFont9+tsBold,
    viewJustify: 8388610,
    _proto: protoStaticText,
    debug: "statusBoxLabel"
   };



receiveBtn := /* child of slurpBaseView */
   {text: "Receive...",
    buttonClickScript:
      func()
      begin
         numEntries := 0;
         if StrEqual(self.text, "Receive...") then
         begin
            Perform(self._parent, 'epInit, []);
      
            Perform(self._parent, 'epConnect, []);
      
            SetValue(self, 'text, "Disconnect");
         end;
         else
         begin
            Perform(self._parent, 'epDisconnect, []);
            SetValue(self, 'text, "Receive...");
         end;
      //   PlaySound(slurpSound);
      end,
    viewBounds: {left: 52, top: 164, right: 184, bottom: 179},
    _proto: protoTextButton,
    debug: "receiveBtn"
   };
// View receiveBtn is declared to slurpBaseView




// ---- File protoVT42 ----
protoVT42 :=
   {viewFlags: 67108923,
    viewFormat: 337,
    newmsg:
      func(msg)
      begin
         if lastChat then
            while Ticks() - lastChat < 10 do begin
               // Nothing...
            end;
         else
            lastChat := Ticks();
      
         SetValue(self.term, 'text, msg);
         SetValue(self.term, 'viewBounds, viewBounds);
      
         RefreshViews();
      end,
    lastChat: nil,
    viewclass: 77,
    debug: "protoVT42"
   };

term := /* child of protoVT42 */
   {viewFlags: 67108923,
    viewFormat: 257,
    viewlinespacing: 13,
    viewFont: simpleFont9,
    viewSetupFormScript:
      func()
      begin
         inherited:?viewSetupFormScript();
         self.viewBounds := Clone(viewBounds);
         viewBounds.right := viewBounds.right - viewBounds.left - 2;
         viewBounds.left := 2;
         viewBounds.bottom := viewBounds.bottom - viewBounds.top - 2;
         viewBounds.top := 2;
      end,
    viewclass: 81,
    debug: "term"
   };
// View term is declared to protoVT42




// ---- Back in File SlurpBaseView.t ----
statusBox := /* child of slurpBaseView */
   {viewBounds: {left: 12, top: 33, right: 225, bottom: 62},
    _proto: protoVT42,
    debug: "statusBox"
   };
// View statusBox is declared to slurpBaseView



epStateLabel := /* child of slurpBaseView */
   {text: "Connection State:",
    viewBounds: {left: 63, top: 185, right: 170, bottom: 199},
    viewClickScript:
      func(unit)
      begin
         epState:showState("Current state:");
      end,
    viewFlags: 515,
    viewFont: simpleFont9+tsBold,
    viewJustify: 8388610,
    _proto: protoStaticText,
    debug: "epStateLabel"
   };
// View epStateLabel is declared to slurpBaseView



epState := /* child of slurpBaseView */
   {viewBounds: {left: 15, top: 199, right: 216, bottom: 216},
    lastShowTime: nil,
    showState:
      func(msg)
      begin
         local theState := commEndPt:State();
      
         if theState then begin
            if lastShowTime then
               while Ticks() - lastShowTime < 10 do begin
                  // Nothing...
               end;
      
            :newMsg(msg && stateLabels[theState]);
            RefreshViews();
      
            lastShowTime := Ticks();
         end;
      end,
    stateLabels:
      [ "Uninitialized",
                              "Unbound",
                              "Idle",
                              "Out Conn Pending",
                              "In Conn Pending",
                              "Data Transfer",
                              "Out Release Pending",
                              "In Release Pending",
                              "In Flux"],
    _proto: protoVT42,
    debug: "epState"
   };
// View epState is declared to slurpBaseView



_view000 := /* child of slurpBaseView */
   {text: "Soup:",
    viewBounds: {left: 11, top: 66, right: 43, bottom: 81},
    _proto: protoStaticText
   };



soupNameDisplay := /* child of slurpBaseView */
   {text: "",
    viewBounds: {left: 42, top: 67, right: 99, bottom: 81},
    viewFont: simpleFont9,
    viewFormat: 337,
    _proto: protoStaticText,
    debug: "soupNameDisplay"
   };
// View soupNameDisplay is declared to slurpBaseView



_view001 := /* child of slurpBaseView */
   {text: "Entries Slurped:",
    viewBounds: {left: 99, top: 66, right: 189, bottom: 82},
    viewJustify: 8388610,
    _proto: protoStaticText
   };



entriesSlurped := /* child of slurpBaseView */
   {text: "0",
    viewBounds: {left: 187, top: 67, right: 226, bottom: 81},
    viewFont: simpleFont9,
    viewFormat: 337,
    viewJustify: 8388610,
    _proto: protoStaticText,
    debug: "entriesSlurped"
   };
// View entriesSlurped is declared to slurpBaseView



_view002 := /* child of slurpBaseView */
   {text: "Current Entry:",
    viewBounds: {left: 76, top: 82, right: 157, bottom: 97},
    _proto: protoStaticText
   };



currentEntryDisplay := /* child of slurpBaseView */
   {viewBounds: {left: 12, top: 97, right: 222, bottom: 155},
    _proto: protoVT42,
    debug: "currentEntryDisplay"
   };
// View currentEntryDisplay is declared to slurpBaseView







// ---- Beginning of section for non used Layout files ----

// End of output